package test;

import java.lang.reflect.*;
import java.net.URLClassLoader;
import java.util.Arrays;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.shadow.com.univocity.parsers.tsv.TsvFormat;
import org.omg.CORBA.PUBLIC_MEMBER;
import java.lang.reflect.*;

@SuppressWarnings("unused")
public class 反射 {
	
	
	public static void main(String[] args) {
		反射 fs = new 反射(0, null);
		//实例化--正向映射
			//通过类得到对象
		//反射--反向反射
			//通过对象得到类
			//科技理解为反向实例化
			/**
			 * 作用：
			 * 	得到一个类的描述
			 *  使用该描述实例化类
			 * */
		
			//1-大写的C，Class:类的描述
			//用对象得到类的描述
				//普通写法
				Class c11 = fs.getClass();
				//泛型写法
				Class<? extends 反射> c1 = fs.getClass();
			//用类得到类的描述
				//普通写法
				Class c22 = 反射.class;
				//泛型写法
				Class<反射> c2 = 反射.class;
			//八种数据类型都可以
		//看看这些东西是什么
		System.out.println(c1);
		System.out.println(c2);
		System.out.println(c11);
		System.out.println(c22);
		System.out.println(int.class);
		//三种方法得到反射
			//1. 通过类.Class
			//2. 通过对象.Class
			//3. 通过CLass<?> c3 = Class.forName("demo211203.TestB");			//需要知道全类名，并且全类名对应的类是谁要知道
			//4. (不要求会)单独获得某个类的描述,
		//第四种：使用url，不需要对象，也不需要类，找到某个工程的bin路径，"file:///D://file//file.java"，找到一个类对应的全文件名
//		URL url = new URL("");
//		URL[] urls = new URL[] {url};
//		URLClassLoader load = new URLClassLoader.newInstance(urls);
//		Class<?> c4 = load.loadClass("");
		//除了方法体中的东西都可以描述反射
		
/**		如何获取一个class的Class实例？有三个方法：*/
//方法一：直接通过一个class的静态变量class获取：
		Class cls0 = String.class;
//方法二：如果我们有一个实例变量，可以通过该实例变量提供的getClass()方法获取：
		String s = "Hello";
		Class cls1 = s.getClass();
//方法三：如果知道一个class的完整类名，可以通过静态方法Class.forName()获取：
		try {
			Class cls2 = Class.forName("java.lang.String");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}
	//2-创建实例
//===============================================================================================================
//===============================================================================================================
	//以下内容为构造器原始笔记，不易理解，已经废弃，新的Constructors笔记在另一个文件
//===============================================================================================================
//===============================================================================================================
	@Test
	public void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		反射 tb = new 反射(0);
		Class<?> c3 = Class.forName("demo211203.反射");
		//得到类的描述之后借助他的方法实例化对象
		Object t1 = c3.newInstance();	//使用反射得到对象|默认构造方法|
		
		Constructor<?>[] cons = c3.getConstructors();	//构造器
		System.out.println(Arrays.toString(cons));
		

		System.out.println(Arrays.toString(cons));
		Constructor<?>[] cons2 = c3.getDeclaredConstructors();
//		System.out.println(Arrays.toString(Arrays.toString(cons2)));
		
		try {
			Constructor<?> cs1 = c3.getConstructor(int.class);
		} catch (NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}							//得到构造方法参数类型的()构造方法返回,根据传进来的参数来判断是获取的哪个构造方法
		try {
			Constructor<?> cs2 = c3.getDeclaredConstructor(int.class,String.class);
		} catch (NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 	//得到的是第二个有两个参数的构造方法
			
	}
	public 反射(int a) {
		
	}
	public 反射(int a,String b) {
		
	}
	/**构造器不会的内容：
	反射得到类的描述的三种方式
	使用构造器如何得到类的描述
	如何利用反射，实例化出对象*/
		//使用自动向上转型的方式定义新的对象
		Class<?> c3 = Class.forName("com.mysql.cj.jdbc.Driver");
		Constructor<?> cs1 = c3.getConstructor(int.class);
		Object object = cs1.newInstance(11);	//其中的参数要根据该类中的构造方法有几种参数类型决定
		//还可以根据这个类的描述得到其中的方法
		java.lang.reflect.Method[] md1 = c3.getMethods();//得到公有的方法
		java.lang.reflect.Method[] md2 = c3.getDeclaredMethods();//得到所有的方法(除构造方法)
		//反射的强大之处：强制访问私有方法
		java.lang.reflect.Method mdd = c3.getMethod("exe",String.class,int.class);
		mdd.setAccessible(true);				//取消访问限制,把private设置为可以访问
		//普通调用方法
		mdd.invoke(c3.newInstance(),"aa",11);	//调用
		//静态调用方法
		md1.invoke("null","aa",11);
		//获得变量
		public void test4() throws ClassNotFoundException{
			Class<?> c3 = Class.forName("类全名");
			Field[] fds = c3.getFields();//一个类中所定义出来的字段
			//其他用法，触类旁通，得到一个或者所有字段
			//Declared可以得到私有，如果要得到一个，给形参赋值
			c3.getDeclaredFields();
			c3.getDeclaredField("");
			c3.getField("");
			//举例：先看正向的非映射赋值方法
			TestB t1 = new TestB();
			int k = t1.a;
			t1.a=100;
			//再看反向的映射赋值方法
			Field fd1;
			Object val = fd1.get(c3.newInstance());
		}
		static void exe(String a, int b){
			System.out.println(a);
			System.out.println(b);
		}
		//重点总结：
		//1. 如何得到类的描述
		//2. 类的描述/构造器，两种方法创建对象
		//3. 取消访问限制
		//4. 了解哪个方法再定义和使用的时候需要什么参数，不定参数的规则
		//5. 类中的成员变量如何反射，得到一个或多个，私有还是公有
}




